package com.uw.gateway.handler.router;

import com.uw.uwrpc.core.api.LoadBalancer;
import com.uw.uwrpc.core.api.RegistryCenter;
import com.uw.uwrpc.core.meta.InstanceMeta;
import com.uw.uwrpc.core.meta.ServiceMeta;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class GatewayRouterHandler {

    private final LoadBalancer<InstanceMeta> loadBalancer;
    private final RegistryCenter registryCenter;

    public Mono<ServerResponse> handle(ServerRequest request) {
        // 1. 根据请求路径拿到 serviceSign。
        String path = request.path().substring(4);
        log.info("request serviceSign：{}", path);
        ServiceMeta serviceMeta = ServiceMeta.fromServiceSign(path);

        // 2. 从注册中心中获取实例列表。
        List<InstanceMeta> instanceMetas = registryCenter.fetchAll(serviceMeta);
        if (CollectionUtils.isEmpty(instanceMetas)) {
            throw new RuntimeException("fetch all instance is null.");
        }

        // 3. 根据指定路由算法选取指定实例
        InstanceMeta choose = loadBalancer.choose(instanceMetas);

        // 4. 获取请求的报文
        Mono<String> requestMono = request.bodyToMono(String.class);

        String url = choose.toUrl();
        log.info("request url：{}", url);
        return requestMono.flatMap(x -> {
            // 5. 通过webclient发送post请求
            WebClient client = WebClient.create(url);
            Mono<ResponseEntity<String>> entity = client.post()
                    .header("Content-Type", "application/json")
                    .bodyValue(x)
                    .retrieve()
                    .toEntity(String.class);
            // 6. 通过entity获取响应报文
            Mono<String> body = entity.map(ResponseEntity::getBody);
            body.subscribe(source -> log.info("response:" + source));
            // 7. 组装响应报文
            return ServerResponse.ok()
                    .header("Content-Type", "application/json")
                    .header("uw.gw.version", "v1.0.0")
                    .body(body, String.class);
        });
    }


}
